/**
 * @file scififo.c
 * @author Linquan
 * @brief 
 * @version 1.1
 * @date 2025-07-28
 * 
 * @copyright Copyright (c) 2023
 * @history
 *		修复 在缓冲区完全覆盖后，无法正确获得缓冲区中数据长度。
 */

#include "scififo.h"

#include  "string.h"


#ifndef min
#define min(x,y) ((x)<(y)?(x):(y))
#endif

/**********************************************************************
 * FIFO输入 内部函数： 传入偏移量，在该偏移量之后追加数据
 **********************************************************************/
static void kfifo_copy_in(struct scififo_t *fifo, const void *src, uint16_t len, uint16_t off)
{
	uint16_t size = fifo->mask + 1;
	uint16_t esize = fifo->type_size;
	uint16_t unused_len;

	off &= fifo->mask;
	if (esize != 1) {
		off *= esize;
		size *= esize;
		len *= esize;
	}

	unused_len = min(len, size - off); 

	memcpy((unsigned char*)fifo->data + off, src, unused_len);
	memcpy(fifo->data, (unsigned char*)src + unused_len, len - unused_len);
	/*
	 * make sure that the data in the fifo is up to date before
	 * incrementing the fifo->in index counter
	 */
}


/**************************************************************************
 *  FIFO输出  内部函数: 传入 数组的偏移量，读出该偏移量后的len个数据
 ****************************************************************************/
static void kfifo_copy_out(struct scififo_t *fifo, void *dst, uint16_t len, uint16_t off)
{
	uint16_t size = fifo->mask + 1;
	uint16_t esize = fifo->type_size;
	uint16_t used_len;

	off &= fifo->mask;
	if (esize != 1) {
		off *= esize;
		size *= esize;
		len *= esize;
	}

	used_len = min(len, size - off);

	memcpy(dst, (unsigned char *)fifo->data + off, used_len);
	memcpy((unsigned char*)dst + used_len, fifo->data, len - used_len);
	/*
	 * make sure that the data is copied before
	 * incrementing the fifo->out index counter
	 */
}

/** 从 缓冲区里读取len个 数据 */
static uint16_t __kfifo_out_peek(struct scififo_t *fifo, void *buf, uint16_t len)
{
	uint16_t used_len;

	used_len = fifo->in - fifo->out;
	if (len > used_len)
		len = used_len;

    if(buf != NO_BUFF)
    {
        kfifo_copy_out(fifo, buf, len, fifo->out);
    }	

	return len;
}




static inline uint16_t kfifo_unused(struct scififo_t *fifo)
{
	return (fifo->mask + 1) - (fifo->in - fifo->out);
}




/**
 * @brief 往fifo中追加 数据
 * 
 * @param fifo 
 * @param c 
 */
uint16_t _scififo_append(struct scififo_t *fifo, const void *buf, uint16_t data_num) 
{
    uint16_t unused_len;

	unused_len = kfifo_unused(fifo);
	if (data_num > unused_len)
		data_num = unused_len;

	kfifo_copy_in(fifo, buf, data_num, fifo->in);
	fifo->in += data_num;
	return data_num;

}


 /**
  * @brief 从out处 抛数据，删除原始数据
  * 
  * @param fifo 
  * @param buf 填入 NO_BUFF，可以只删除，不进行读取
  * @param len 
  * @return uint16_t 
  */
uint16_t _scififo_remove(struct scififo_t *fifo, void *buf, uint16_t data_num)
{
    data_num = __kfifo_out_peek(fifo, buf, data_num);
	fifo->out += data_num;
	return data_num;

}



/**
 * @brief 从out处往后定位读第index个数据，原始数据不动
 * 
 * @param fifo 
 * @param n 
 * @return uint8_t 
 */
uint16_t _scififo_at_out(struct scififo_t *fifo, void *buf, uint16_t index)
{
    uint16_t offset = fifo->out + index;

    kfifo_copy_out(fifo, buf, 1, offset);  
	return 1;
}


/**
 * @brief 从in指针定位往前读第index个数据，原始数据不动
 * 
 */
uint16_t _scififo_at_in(struct scififo_t *fifo, void *buf, uint16_t index)
{
	uint16_t offset = fifo->in - index -1;

	kfifo_copy_out(fifo, buf, 1, offset);  
	return 1;
}


/**
 * @brief 
 * @param fifo 
 */
void _scififo_clear(struct scififo_t *fifo) {
    fifo->in = fifo->out;
}

/**
 * @brief 
 * @param fifo
 * @return uint16_t
 */
uint16_t _scififo_length(struct scififo_t *fifo) {
    return (fifo->in - fifo->out);
}



